#include "../stdafx.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

#include "../include/Platform.h"

#include "../util/util.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "Decoration.h"
namespace soy {

Decoration::Decoration( int indicator_ ) : next( 0 ), indicator( indicator_ ) {
}

Decoration::~Decoration() {
}

bool Decoration::Empty() {
	return rs.Runs() == 1;
}

DecorationList::DecorationList() : currentIndicator( 0 ), currentValue( 1 ), current( 0 ),
	lengthDocument( 0 ), root( 0 ), clickNotified( false ) {
}

DecorationList::~DecorationList() {
	Decoration* deco = root;
	while ( deco ) {
		Decoration* decoNext = deco->next;
		delete deco;
		deco = decoNext;
	}
	root = 0;
	current = 0;
}

Decoration* DecorationList::DecorationFromIndicator( int indicator ) {
	for ( Decoration* deco = root; deco; deco = deco->next ) {
		if ( deco->indicator == indicator ) {
			return deco;
		}
	}
	return 0;
}

Decoration* DecorationList::Create( int indicator, int length ) {
	currentIndicator = indicator;
	Decoration* decoNew = new Decoration( indicator );
	decoNew->rs.InsertSpace( 0, length );
	Decoration* decoPrev = 0;
	Decoration* deco = root;
	while ( deco && ( deco->indicator < indicator ) ) {
		decoPrev = deco;
		deco = deco->next;
	}
	if ( decoPrev == 0 ) {
		decoNew->next = root;
		root = decoNew;
	} else {
		decoNew->next = deco;
		decoPrev->next = decoNew;
	}
	return decoNew;
}

void DecorationList::Delete( int indicator ) {
	Decoration* decoToDelete = 0;
	if ( root ) {
		if ( root->indicator == indicator ) {
			decoToDelete = root;
			root = root->next;
		} else {
			Decoration* deco = root;
			while ( deco->next && !decoToDelete ) {
				if ( deco->next && deco->next->indicator == indicator ) {
					decoToDelete = deco->next;
					deco->next = decoToDelete->next;
				} else {
					deco = deco->next;
				}
			}
		}
	}
	if ( decoToDelete ) {
		delete decoToDelete;
		current = 0;
	}
}

void DecorationList::SetCurrentIndicator( int indicator ) {
	currentIndicator = indicator;
	current = DecorationFromIndicator( indicator );
	currentValue = 1;
}

void DecorationList::SetCurrentValue( int value ) {
	currentValue = value ? value : 1;
}

bool DecorationList::FillRange( int& position, int value, int& fillLength ) {
	if ( !current ) {
		current = DecorationFromIndicator( currentIndicator );
		if ( !current ) {
			current = Create( currentIndicator, lengthDocument );
		}
	}
	bool changed = current->rs.FillRange( position, value, fillLength );
	if ( current->Empty() ) {
		Delete( currentIndicator );
	}
	return changed;
}

void DecorationList::InsertSpace( int position, int insertLength ) {
	lengthDocument += insertLength;
	for ( Decoration* deco = root; deco; deco = deco->next ) {
		deco->rs.InsertSpace( position, insertLength );
	}
}

void DecorationList::DeleteRange( int position, int deleteLength ) {
	lengthDocument -= deleteLength;
	Decoration* deco;
	for ( deco = root; deco; deco = deco->next ) {
		deco->rs.DeleteRange( position, deleteLength );
	}
	DeleteAnyEmpty();
}

void DecorationList::DeleteAnyEmpty() {
	Decoration* deco = root;
	while ( deco ) {
		if ( deco->Empty() ) {
			Delete( deco->indicator );
			deco = root;
		} else {
			deco = deco->next;
		}
	}
}

int DecorationList::AllOnFor( int position ) {
	int mask = 0;
	for ( Decoration* deco = root; deco; deco = deco->next ) {
		if ( deco->rs.ValueAt( position ) ) {
			mask |= 1 << deco->indicator;
		}
	}
	return mask;
}

int DecorationList::ValueAt( int indicator, int position ) {
	Decoration* deco = DecorationFromIndicator( indicator );
	if ( deco ) {
		return deco->rs.ValueAt( position );
	}
	return 0;
}

int DecorationList::Start( int indicator, int position ) {
	Decoration* deco = DecorationFromIndicator( indicator );
	if ( deco ) {
		return deco->rs.StartRun( position );
	}
	return 0;
}

int DecorationList::End( int indicator, int position ) {
	Decoration* deco = DecorationFromIndicator( indicator );
	if ( deco ) {
		return deco->rs.EndRun( position );
	}
	return 0;
}

};
